
#define LOG_NDEBUG 0
#define LOG_TAG "SomeIPCLient"
#include <vsomeip/vsomeip.hpp>
#include <memory>
#include "log/log_main.h"
#include <mutex>
#include <condition_variable>
#include <thread>
#include <iomanip>
#include <iostream>
#include <sstream>

std::shared_ptr<vsomeip::application> app;
std::mutex mutex;
std::condition_variable condition;

void run() {
    
    std::unique_lock<std::mutex> its_lock(mutex);
    condition.wait(its_lock);
	// Register to listen 
    ALOGD("Register to listen ");
    std::set<vsomeip::eventgroup_t> its_groups;
    its_groups.insert(0x4444);
    app->request_event(707, 0x01, 1, its_groups, true);
    app->subscribe(707, 0x01, 0x4444);

    // Send Request
    std::shared_ptr<vsomeip::message> rq = vsomeip::runtime::get()->create_request(true);
    // Set the hello world service as target of the request
    rq->set_service(605);
    rq->set_instance(0x01);
    rq->set_method(2);
    rq->set_message_type(vsomeip::message_type_e::MT_REQUEST_NO_RETURN);
    // Create a payload which will be sent to the service
    std::shared_ptr<vsomeip::payload> pl = vsomeip::runtime::get()->create_payload();
    std::string str;
    for(int i=0;i<90;i++){
        str.append("1");
    }
    std::vector<vsomeip::byte_t> pl_data(std::begin(str), std::end(str));

    pl->set_data(pl_data);
    rq->set_payload(pl);
    ALOGD("send 605 2");
    app->send(rq);
}


void on_message(const std::shared_ptr<vsomeip::message>& _response) {
    
    std::stringstream its_message;
    its_message << "CLIENT: received a notification for event [" << std::setw(4)
                << std::setfill('0') << std::hex << _response->get_service() << "." << std::setw(4)
                << std::setfill('0') << std::hex << _response->get_instance() << "." << std::setw(4)
                << std::setfill('0') << std::hex << _response->get_method()
                << "message_type: " << std::hex << static_cast<int>(_response->get_message_type())
                << "] to Client/Session [" << std::setw(4) << std::setfill('0') << std::hex
                << _response->get_client() << "/" << std::setw(4) << std::setfill('0') << std::hex
                << _response->get_session() << "] = ";
    std::shared_ptr<vsomeip::payload> its_payload = _response->get_payload();
    its_message << "(" << std::dec << its_payload->get_length() << ") ";
    for (uint32_t i = 0; i < its_payload->get_length(); ++i)
        its_message << std::hex << std::setw(2) << std::setfill('0')
                    << (int)its_payload->get_data()[i] << " ";
    std::cout << its_message.str() << std::endl;

}

void on_availability(vsomeip::service_t _service, vsomeip::instance_t _instance,
                     bool _is_available) {
    
    std::cout << "CLIENT: Service [" << std::setw(4) << std::setfill('0') << std::hex << _service
              << "." << _instance << "] is " << (_is_available ? "available." : "NOT available.")
              << std::endl;
    if (_is_available) {
    
        condition.notify_one();
    }
}

void on_state_cbk(vsomeip::state_type_e _state) {
    
    std::cout << "on_state_cbk, state: " << static_cast<int>(_state) << std::endl;
    if (_state == vsomeip::state_type_e::ST_REGISTERED) {
    
        // After successful registration, request service, And then wait on_availability Of callback
        // we are registered at the runtime now we can request the service
        // and wait for the on_availability callback to be called
        app->request_service(605, 0x01);
        app->request_service(707, 0x01);
        
    }
}

int main(int argc, char **argv){

    app = vsomeip::runtime::get()->create_application("SomeIPTestClient");

    std::set<vsomeip::eventgroup_t> its_groups;
    its_groups.insert(0x4444);

    app->init();

    // Put this application Register in the routing manager ,on_state_cbk：callback Registration results 
    app->register_state_handler(on_state_cbk);

    app->register_availability_handler(707, 0x01, on_availability);
    app->register_message_handler(vsomeip::ANY_SERVICE, vsomeip::ANY_INSTANCE, vsomeip::ANY_METHOD,
                                on_message);
    std::thread sender(run);
    app->start();
    return 0;
}